/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package eu.fastl.dragster.loadgen;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import eu.fastl.dragster.loadgen.impl.HttpLoadGenerator;
import eu.fastl.dragster.loadgen.impl.HttpLoadGeneratorConfig;

/**
 * Command line tool for firing HTTP queries on to an application
 * @author Ernst Fastl
 */
public class HttpLoadGeneratorExec {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpLoadGeneratorExec.class);

    private static final String OPTION_FILE_NAME_DESCRIPTION = "A text file containing one url per line and potentially "
            + "${propertyName} expressions which will be substituted at runtime";
    private static final String OPTION_FILE_NAME_LONG_NAME = "file-name";

    public static void main(String[] args) {
        HttpLoadGeneratorConfig generatorConfig = new HttpLoadGeneratorConfig();
        Options options = createOptions();

        CommandLineParser parser = new PosixParser();
        CommandLine cmdLine = null;
        try {
            cmdLine = parser.parse(options, args);
        } catch (ParseException e) {
            LOGGER.error("Exception while parsing Command Line Arguments", e);
            System.out.println("");
            printHelpAndExit(options);
        }
        if (cmdLine.hasOption("h")) {
            printHelpAndExit(options);
        }
        if (cmdLine.hasOption("v")) {
            printVersion();
            System.exit(1);
        }

        if (cmdLine.hasOption("f")) {
            if (cmdLine.hasOption("u")) {
                System.out.println("You can only specify either a file -f or a url -u\n");
                printHelpAndExit(options);
            } else {
                generatorConfig.setFileName(cmdLine.getOptionValue("f"));
            }
        } else {
            if (cmdLine.hasOption("u")) {
                generatorConfig.setUrl(cmdLine.getOptionValue("u"));
            } else {
                System.out.println("You must specify either a file -f or a url -u\n");
                printHelpAndExit(options);
            }
        }

        if (cmdLine.hasOption("t")) {
            generatorConfig.setNumThreads(Integer.parseInt(cmdLine.getOptionValue("t")));
        }
        if (cmdLine.hasOption("n")) {
            generatorConfig.setNumRuns(Integer.parseInt(cmdLine.getOptionValue("n")));
        }
        if (cmdLine.hasOption("d")) {
            generatorConfig.setDryRun(true);
        }
        if(cmdLine.hasOption("s")){
            generatorConfig.setSeconds(Integer.parseInt(cmdLine.getOptionValue("s")));
        }
        HttpLoadGenerator generator = new HttpLoadGenerator(generatorConfig);
        generator.run();
    }

    private static void printHelpAndExit(Options options) {
        printHelp(options);
        System.exit(1);
    }

    private static void printVersion() {
        System.out.println("Dragster Load Generator v0.1");
    }

    private static void printHelp(Options options) {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp(HttpLoadGeneratorExec.class.getName(), options);
        System.out.println("");
    }

    @SuppressWarnings("static-access")
    private static Options createOptions() {
        Options retval = new Options();

        Option fileNameOption = OptionBuilder.withLongOpt(OPTION_FILE_NAME_LONG_NAME)
                .withDescription(OPTION_FILE_NAME_DESCRIPTION).hasArg().withArgName("filename").create("f");

        Option numThreadsOption = OptionBuilder.withLongOpt("num-threads")
                .withDescription("Number of concurrent threads to create (default=10)").hasArg().withArgName("NUMBER")
                .withType(Integer.class).create("t");

        Option numRunsOption = OptionBuilder.withLongOpt("num-runs")
                .withDescription("Number of times to run 0 is infinite (default=1)").hasArg()
                .withArgName("NUMBER").withType(Integer.class).create("n");

        Option secondsOption = OptionBuilder.withLongOpt("seconds")
        .withDescription("Number of seconds to run 0 is infinite (default=0)").hasArg()
        .withArgName("NUMBER").withType(Integer.class).create("s");

        Option urlOption = OptionBuilder.withLongOpt("url").withDescription("Url to query").hasArg().withArgName("URL")
                .withType(Integer.class).create("u");

        Option dryRunOption = OptionBuilder
                .withLongOpt("dry-run")
                .withDescription(
                        "run through the scenario file, output the queries that would be executed without actually executing them")
                .create("d");

        Option versionOption = OptionBuilder.withLongOpt("version")
                .withDescription("display the current version number of the application").create("v");

        Option helpOption = OptionBuilder.withLongOpt("help").withDescription("display this help screen").create("h");

        retval.addOption(fileNameOption);
        retval.addOption(numThreadsOption);
        retval.addOption(versionOption);
        retval.addOption(helpOption);
        retval.addOption(numRunsOption);
        retval.addOption(dryRunOption);
        retval.addOption(urlOption);
        retval.addOption(secondsOption);

        return retval;
    }
}
